package
{
	import flash.display.*;
	import flash.events.ContextMenuEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.*;
	import flash.net.*;
	import flash.system.*;
	import flash.ui.*;
	import flash.utils.*;
	
	/**
	 * 概览管理器
	 * @author Dalton
	 * 
	 */    
	public class ProfilerManager
	{
		private var itvTime:int;
		private var initTime:int;
		private var currentTime:int;
		private var frameCount:int;
		private var totalCount:int;
		public var minFps:Number;
		public var maxFps:Number;
		public var minMem:Number;
		public var maxMem:Number;
		public var history:int = 60;
		public var fpsList:Array = [];
		public var memList:Array = [];
		public var displayed:Boolean = false;
		private var started:Boolean = false;
		private var inited:Boolean = false;
		private var frame:Sprite;
		public var stage:Stage;
		private var content:ProfilerContent;
		
		public function ProfilerManager(s:Stage) {
			init(s);
		}
		
		public function menuHandler(e:ContextMenuEvent):void
		{
			if (stage.displayState != flash.display.StageDisplayState.NORMAL)
			{
				e.target.customItems[0].enabled = false;
				e.target.customItems[1].enabled = true;
			}
			else 
			{
				e.target.customItems[0].enabled = true;
				e.target.customItems[1].enabled = false;
			}
			return;
		}
		
		public function init(s:Stage):void
		{
			if (inited)
			{
				return;
			}
			inited = true;
			stage = s;
			content = new ProfilerContent();
			frame = new Sprite();
			minFps = Number.MAX_VALUE;
			maxFps = Number.MIN_VALUE;
			minMem = Number.MAX_VALUE;
			maxMem = Number.MIN_VALUE;
			start();
		}
		
		public function start():void
		{
			if (started)
			{
				return;
			}
			started = true;
			var currentTime:int;
			itvTime = currentTime = flash.utils.getTimer();
			initTime = currentTime;
			frameCount = currentTime = 0;
			totalCount = currentTime;
			//addEvent(frame, Event.ENTER_FRAME, draw);
		}
		
		public function stop():void
		{
			if (!started)
			{
				return;
			}
			started = false;
			removeEvent(frame, Event.ENTER_FRAME, draw);
		}
		
		public function get currentFps():Number
		{
			return frameCount / intervalTime;
		}
		
		public function get currentMem():Number
		{
			return flash.system.System.totalMemory / 1024 / 1000;
		}
		
		public function get averageFps():Number
		{
			return totalCount / runningTime;
		}
		
		private function get runningTime():Number
		{
			return (currentTime - initTime) / 1000;
		}
		
		private function get intervalTime():Number
		{
			return (currentTime - itvTime) / 1000;
		}
		
		public function toggleDisplay():void
		{
			if (displayed) {
				hide();
			}
			else {
				show();
			}
		}
		
		private function show():void
		{
			displayed = true;
			addEvent(stage, Event.RESIZE, resize);
			stage.addChild(content);
			updateDisplay();
		}
		
		private function hide():void
		{
			displayed = false;
			removeEvent(stage, Event.RESIZE, resize);
			stage.removeChild(content);
		}
		
		private function resize(e:Event):void
		{
			content.update(runningTime, minFps, maxFps, minMem, maxMem, currentFps, currentMem, averageFps, fpsList, memList, history);
			return;
		}
		
		public function draw():void
		{
			currentTime = flash.utils.getTimer();
			frameCount++;
			totalCount++;
			if (intervalTime >= 1)
			{
				if (displayed)
				{
					updateDisplay();
				}
				else 
				{
					updateMinMax();
				}
				fpsList.unshift(currentFps);
				memList.unshift(currentMem);
				if (fpsList.length > history)
				{
					fpsList.pop();
				}
				if (memList.length > history)
				{
					memList.pop();
				}
				itvTime = currentTime;
				frameCount = 0;
			}
			return;
		}
		
		private function updateDisplay():void
		{
			updateMinMax();
			content.update(runningTime, minFps, maxFps, minMem, maxMem, currentFps, currentMem, averageFps, fpsList, memList, history);
			return;
		}
		
		private function updateMinMax():void
		{
			minFps = Math.min(currentFps, minFps);
			maxFps = Math.max(currentFps, maxFps);
			minMem = Math.min(currentMem, minMem);
			maxMem = Math.max(currentMem, maxMem);
			return;
		}
		
		private function addEvent(e:EventDispatcher, eventType:String, func:Function):void
		{
			e.addEventListener(eventType, func, false, 0, true);
			return;
		}
		
		private function removeEvent(e:EventDispatcher, eventType:String, func:Function):void
		{
			e.removeEventListener(eventType, func);
			return;
		}
		
	}
}

import flash.display.*;
import flash.events.Event;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;



class ProfilerContent extends Sprite
{
	
	private var minFpsTxtBx:TextField;
	private var maxFpsTxtBx:TextField;
	private var minMemTxtBx:TextField;
	private var maxMemTxtBx:TextField;
	private var infoTxtBx:TextField;
	private var box:flash.display.Shape;
	private var fps:flash.display.Shape;
	private var mb:flash.display.Shape;
	
	public function ProfilerContent()
	{
		this.fps = new Shape();
		this.mb = new Shape();
		this.box = new Shape();
		this.mouseChildren = false;
		this.mouseEnabled = false;
		this.fps.x = 65;
		this.fps.y = 45;
		this.mb.x = 65;
		this.mb.y = 90;
		var tf:TextFormat = new TextFormat("_sans", 9, 0xAAAAAA);
		this.infoTxtBx = new TextField();
		this.infoTxtBx.autoSize = TextFieldAutoSize.LEFT;
		this.infoTxtBx.defaultTextFormat = new TextFormat("_sans", 11, 0xCCCCCC);
		this.infoTxtBx.y = 98;
		this.minFpsTxtBx = new TextField();
		this.minFpsTxtBx.autoSize = TextFieldAutoSize.LEFT;
		this.minFpsTxtBx.defaultTextFormat = tf;
		this.minFpsTxtBx.x = 7;
		this.minFpsTxtBx.y = 37;
		this.maxFpsTxtBx = new TextField();
		this.maxFpsTxtBx.autoSize = TextFieldAutoSize.LEFT;
		this.maxFpsTxtBx.defaultTextFormat = tf;
		this.maxFpsTxtBx.x = 7;
		this.maxFpsTxtBx.y = 5;
		this.minMemTxtBx = new TextField();
		this.minMemTxtBx.autoSize = TextFieldAutoSize.LEFT;
		this.minMemTxtBx.defaultTextFormat = tf;
		this.minMemTxtBx.x = 7;
		this.minMemTxtBx.y = 83;
		this.maxMemTxtBx = new TextField();
		this.maxMemTxtBx.autoSize = TextFieldAutoSize.LEFT;
		this.maxMemTxtBx.defaultTextFormat = tf;
		this.maxMemTxtBx.x = 7;
		this.maxMemTxtBx.y = 50;
		addChild(this.box);
		addChild(this.infoTxtBx);
		addChild(this.minFpsTxtBx);
		addChild(this.maxFpsTxtBx);
		addChild(this.minMemTxtBx);
		addChild(this.maxMemTxtBx);
		addChild(this.fps);
		addChild(this.mb);
		
		this.addEventListener(Event.ADDED_TO_STAGE, this.added, false, 0, true);
		this.addEventListener(Event.REMOVED_FROM_STAGE, this.removed, false, 0, true);
		return;
	}
	
	public function update(runningTime:Number, minFps:Number, maxFps:Number, minMem:Number, maxMem:Number, currentFps:Number, currentMem:Number, averageFps:Number, fpsList:Array, memList:Array, e:int):void
	{
		if (runningTime >= 1)
		{
			this.minFpsTxtBx.text = minFps.toFixed(3) + " Fps";
			this.maxFpsTxtBx.text = maxFps.toFixed(3) + " Fps";
			this.minMemTxtBx.text = minMem.toFixed(3) + " Mb";
			this.maxMemTxtBx.text = maxMem.toFixed(3) + " Mb";
		}
		this.infoTxtBx.text = "Current Fps " + currentFps.toFixed(3) + "   |   Average Fps " + averageFps.toFixed(3) + "   |   Memory Used " + currentMem.toFixed(3) + " Mb";
		this.infoTxtBx.x = stage.stageWidth - this.infoTxtBx.width - 20;
		var gfx:Graphics = this.fps.graphics;
		gfx.clear();
		gfx.lineStyle(1, 0x33FF00, 0.7);
		var i:int = 0;
		var len:uint = fpsList.length;
		var heightMax:Number = 35;
		var contentWidth:Number = stage.stageWidth - 80;
		var deltaX:Number = contentWidth / (e - 1);
		var d:Number = maxFps - minFps;
		var drawY:Number;
		while (i < len) {
			drawY = (fpsList[i] - minFps) / d;
			if (i != 0) {
				gfx.lineTo(i * deltaX, (-drawY) * heightMax);
			}
			else {
				gfx.moveTo(0, (-drawY) * heightMax);
			}
			++i;
		}
		
		
		gfx = this.mb.graphics;
		gfx.clear();
		gfx.lineStyle(1, 0x0066FF, 0.7);
		
		len = memList.length;
		d = maxMem - minMem;
		i = 0;
		while (i < len) {
			drawY = (memList[i] - minMem) / d;
			if (i != 0) {
				gfx.lineTo(i * deltaX, (-drawY) * heightMax);
			}
			else {
				gfx.moveTo(0, (-drawY) * heightMax);
			}
			++i;
		}
		return;
	}
	
	private function added(e:Event):void
	{
		this.resize();
		stage.addEventListener(Event.RESIZE, this.resize, false, 0, true);
		return;
	}
	
	private function removed(e:Event):void
	{
		stage.removeEventListener(Event.RESIZE, this.resize);
		return;
	}
	
	private function resize(e:Event=null):void
	{
		var gfx:Graphics;
		gfx = this.box.graphics;
		gfx.clear();
		gfx.beginFill(0, 0.5);
		gfx.drawRect(0, 0, stage.stageWidth, 120);
		gfx.lineStyle(1, 0xFFFFFF, 0.2);
		gfx.moveTo(65, 45);
		gfx.lineTo(65, 10);
		gfx.moveTo(65, 45);
		gfx.lineTo(stage.stageWidth - 15, 45);
		gfx.moveTo(65, 90);
		gfx.lineTo(65, 55);
		gfx.moveTo(65, 90);
		gfx.lineTo(stage.stageWidth - 15, 90);
		gfx.endFill();
		this.infoTxtBx.x = stage.stageWidth - this.infoTxtBx.width - 20;
		return;
	}
}